package ru.serggt1;

import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.tree.Tree;

/**
 * Hello world!
 *
 */
public class App {

    final static String INPUT = "false or ( false or false or false and true )";

    public static void main(String[] args) throws RecognitionException {
        BooleanExpressionTreeParser parser = new BooleanExpressionTreeParser(
                new CommonTokenStream(new BooleanExpressionTreeLexer(
                new ANTLRStringStream(INPUT))));

        BooleanExpressionTreeParser.boolExpr_return boolExpr = parser.boolExpr();
        System.out.println(calcBoolExpr((Tree) boolExpr.getTree()));
    }

    private static boolean calcBoolExpr(Tree node) {
        if (node.getType() != BooleanExpressionTreeLexer.NODE_BOOL_EXPR) {
            throw new IllegalNodeException(node);
        }

        return calcBoolOr(node.getChild(0));
    }

    private static boolean calcBoolOr(Tree node) {
        if (node.getType() != BooleanExpressionTreeLexer.NODE_OR) {
            throw new IllegalNodeException(node);
        }

        boolean res = false;
        for (int i = 0; i < node.getChildCount(); i++) {
            res = res || calcBoolAnd(node.getChild(i));
            if (res) {
                break;
            }
        }
        return res;
    }

    private static boolean calcBoolAnd(Tree node) {
        if (node.getType() != BooleanExpressionTreeLexer.NODE_AND) {
            throw new IllegalNodeException(node);
        }

        boolean res = true;
        for (int i = 0; i < node.getChildCount(); i++) {
            res = res && calcBoolAtom(node.getChild(i));
            if (!res) {
                break;
            }
        }
        return res;
    }

    private static boolean calcBoolAtom(Tree node) {
        switch (node.getType()) {
            case BooleanExpressionTreeLexer.TRUE:
                return true;
            case BooleanExpressionTreeLexer.FALSE:
                return false;
            case BooleanExpressionTreeLexer.NODE_BOOL_EXPR:
                return calcBoolExpr(node);
            default:
                throw new IllegalNodeException(node);
        }
    }

    private static class IllegalNodeException extends RuntimeException {

        public IllegalNodeException(Tree node) {
            super("" + node.getType() + ": " + node.getText());
        }
    }
}
